#ifndef xpack_interface_can_alloc_seq
#define xpack_interface_can_alloc_seq
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::interface_can_alloc_seq::inc
#include"define/base_type.hpp"
#include"define/nullref.hpp"
#include"interface/ranger.hpp"
#include"interface/seqptr.hpp"
#include"interface/unified_seq.hpp"
#include"macro/xexport.hpp"
#include"meta/function.hpp"
#include"meta/has_cast.hpp"
#include"meta/is_left_ref.hpp"
#include"meta/is_same.hpp"
#include"meta/is_ptr.hpp"
#include"meta/remove_ref.hpp"
#pragma pop_macro("xuser")

namespace mixc::interface_can_alloc_seq{
    template<class functor_t, class item_t = void>
    struct meta{
        static constexpr auto invoke(){
            using func              = inc::function<decltype(& functor_t::operator())>;
            using ret               = typename func::return_type;

            // 把 void 作为模板参数传入 inc::is_unified_seq<> 会错出
            if constexpr (inc::is_same<void, item_t>){
                return
                    (inc::is_ptr<ret> or inc::is_unified_seq<ret>) or
                    (inc::can_unified_seqlize<ret> and inc::is_left_ref<ret>);
            }
            else{
                return
                    (inc::has_cast<ret, item_t * /*要求支持 ret = item_t * 的转换*/> or inc::is_unified_seqx<ret, item_t>) or
                    (inc::can_unified_seqlizex<ret, item_t> and inc::is_left_ref<ret>);
            }
        }
    };

    template<class functor_t>
    inline auto can_alloc_seq_helper(functor_t const & callback){
        return [&](uxx length){
            // decltype(auto) 可以支持左值引用
            decltype(auto) buffer   = callback(length);

            if constexpr (inc::is_ptr<decltype(buffer)>){
                return inc::seqptr<
                    // decltype(*buffer) 会带上引用标记，比如 buffer 是 char * 类型
                    // decltype(*buffer) 会变成 char & 类型
                    inc::remove_ref<decltype(*buffer)>
                >(buffer, buffer ? length : 0);
            }
            // 如果本身就是 unified_seq 类型就无需转换
            else if constexpr (inc::is_unified_seq<decltype(buffer)>){
                return buffer;
            }
            // 避免误用值传递导致缓冲区提前析构
            else{
                static_assert(inc::is_left_ref<decltype(buffer)>);

                if (buffer == inc::nullref){
                    return inc::unified_seq<decltype(buffer)>(nullptr, 0);
                }
                else{
                    return inc::unified_seq<decltype(buffer)>(buffer, length);
                }
            }
        };
    }

    template<class functor_t>
    concept arg_check = requires(functor_t functor, uxx length){
        can_alloc_seq_helper(functor)(length);
    };
}

namespace mixc::interface_can_alloc_seq::origin{
    using ::mixc::interface_can_alloc_seq::can_alloc_seq_helper;

    template<class functor_t>
    concept can_alloc_seq = meta<functor_t>::invoke() == true and arg_check<functor_t>;

    template<class functor_t, class item_t>
    concept can_alloc_seqx = meta<functor_t, item_t>::invoke() == true and arg_check<functor_t>;
}

#endif

xexport_space(mixc::interface_can_alloc_seq::origin)